#include "serveur.h"
#include "md5/md5.h"

using namespace std;

// Initialisation du singleton à NULL
Serveur * Serveur::_singleton = NULL;


// Mutex utilisés :
pthread_mutex_t mutexAjoutPartie = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexSupprimePartie = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutexConnectionNouveauServeurPartie = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_msg_sockNouveauServeurPartie = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutexLectureServeurPartie = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_msg_sockLectureServeurPartie = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutexConnectionClient = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_msg_sockClient = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t mutexLog = PTHREAD_MUTEX_INITIALIZER;


Serveur * Serveur::getInstance (u_short portServeurPartie, u_short portLecture, u_short portLectureServeurPartie,
			u_short portEcouteClientServeurPartie, u_short portEcouteServeurPartie)
{
	if (NULL ==  _singleton)
	{
		std::cout << "Creation du singleton." << std::endl;
		_singleton =  new Serveur(portServeurPartie, portLecture, portLectureServeurPartie,
								portEcouteClientServeurPartie, portEcouteServeurPartie);
	}
	else
	{
		std::cout << "Singleton deja cree !" << std::endl;
	}
	return _singleton;
}

void Serveur::kill()
{
	if (NULL != _singleton)
	{
		delete _singleton;
		_singleton = NULL;
	}
}

int hasard(int min, int max)
{
	srand(time(NULL));
	return (rand() % (max - min + 1)) + min;
}

char * md5_str(char *p)
{
	md5_state_t state;
	md5_byte_t digest[16];
	char *hex_output = (char *)malloc(33);
	int di;

	md5_init(&state);
	md5_append(&state, (const md5_byte_t *)p, (int)strlen(p));
	md5_finish(&state, digest);

	for (di = 0; di < 16; di++)
	{
		sprintf(hex_output + di * 2, "%02x", digest[di]);
	}
	return hex_output;
}

Serveur::Serveur(u_short portServeurPartie, u_short portLecture, u_short portLectureServeurPartie,
			u_short portEcouteClientServeurPartie, u_short portEcouteServeurPartie)
{
	// port d'écoute pour les nouveaux serveurs de partie
	this->portServeurPartie = portServeurPartie;
	// port d'écoute pour les nouveaux clients
	this->portClient = portLecture;
	// port de lecture des serveurs de partie
	this->portLectureServeurPartie = portLectureServeurPartie;

	// port d'écoute du serveur de partie distant
	this->portEcouteServeurPartie = portEcouteServeurPartie;
	// port d'écoute des clients de partie distant
	this->portEcouteClientServeurPartie = portEcouteClientServeurPartie;


	this->sockServeurPartie = this->createSock(this->portServeurPartie);
	this->sockClient = this->createSock(this->portClient);
	this->sockLectureServeurPartie = this->createSock(this->portLectureServeurPartie);


	listen(this->sockServeurPartie, 10);
	listen(this->sockClient, 10);
	listen(this->sockLectureServeurPartie, 10);


	this->numberOfGame = 0;
	this->maxGame = 10;
}

Serveur::~Serveur()
{
	this->close_serveur(this->sockServeurPartie);
	this->close_serveur(this->sockClient);
	this->close_serveur(this->sockLectureServeurPartie);
	this->numberOfGame = 0;
}

int * Serveur::connectionServeurPartie()
{
	while(1)
	{
		pthread_mutex_lock(&mutexConnectionNouveauServeurPartie);
		this->msg_sockServeurPartie = accept(this->sockServeurPartie, NULL, NULL);
		if (this->msg_sockServeurPartie == -1)
		{
			perror("Erreur accept");
		}
		this->initNouveauServeurPartie();
		pthread_mutex_unlock(&mutexConnectionNouveauServeurPartie);
	}
	close(this->msg_sockServeurPartie);
	return 0;
}

void  * Serveur::traiterNouveauServeurPartie()
{
	// réception
	pthread_mutex_lock(&mutex_msg_sockNouveauServeurPartie);
	int socket1 = this->msg_sockServeurPartie;
	pthread_mutex_unlock(&mutex_msg_sockNouveauServeurPartie);

	char * message = (char *)malloc(33);

	struct sockaddr_in from;
	from.sin_port = htons((u_short)this->portServeurPartie);
	unsigned int from_len= sizeof(from);
	if (getpeername(socket1, (struct sockaddr*)&from, &from_len) == -1)
	{
		perror("Erreur d'obtention du nom du correspondant connecte a la socket");
	}
	printf("Connexion avec %s : %d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));

	if (read(socket1, message, 33) == -1)
	{
		perror("Probleme read");
		exit(-1);
	}

	// authentification md5
	char * msg = (char *)malloc(10);
	strcpy(msg, "gameServer");
	char * mesgCrypte = (char *)malloc(33);
	mesgCrypte = md5_str(msg);

	if (strcmp(message, mesgCrypte) == 0)
	{
		// si réussie, ajout à la liste des serveurs de parties
		if (this->addGame(Partie(inet_ntoa(from.sin_addr),
				this->portEcouteClientServeurPartie, 2332, 0, 0, 0, false)) == -1)
		{
			strcpy(message, "echec");
			this->log("\nAjout du nouveau serveur de partie impossible : nombre maximum de parties atteind");
			printf("\nAjout du nouveau serveur de partie impossible :\n");
			printf("Nombre maximum de parties atteind.\n");
		}
		else
		{
			strcpy(message, "succes");
			this->log("Nouveau serveur de partie connecte sur le port 7770");
			printf("\nNouveau serveur de partie connecte : %s.\n", inet_ntoa(from.sin_addr));
			printf("Nombre de parties disponibles : %d\n", this->getNumberOfGame());
		}
	}

	else
	{
		strcpy(message, "echec");
		this->log("Echec de connexion d'un serveur de partie sur le port 7770");
		printf("\nEchec de connexion du serveur de partie : %s\n", inet_ntoa(from.sin_addr));
		printf("Nombre de parties disponibles : %d\n", this->getNumberOfGame());
	}

	free(msg);
	free(mesgCrypte);

	close(socket1);

	// envoie de la réponse
	int sock;
	string NomDistant = inet_ntoa(from.sin_addr);
	struct sockaddr_in adresse;
	struct hostent *recup;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("Erreur ouverture");
	}

	if ((recup = gethostbyname(NomDistant.c_str())) == NULL)
	{
		perror("Erreur obtention adresse");
	}

	memcpy((char *)&adresse.sin_addr, (char *)recup->h_addr, recup->h_length);

	adresse.sin_family = AF_INET;
	adresse.sin_port = htons((u_short)this->portEcouteServeurPartie);
	if (connect(sock, (struct sockaddr *)&adresse, sizeof(adresse)) == -1)
	{
		perror("Erreur connexion");
	}
	if (write(sock, message, strlen(message)) == -1)
	{
		perror("Erreur ecriture");
	}

	free(message);
	close(sock);

	return NULL;
}

int * Serveur::connectionClient()
{
	while(1)
	{
		pthread_mutex_lock(&mutexConnectionClient);
		this->msg_sockClient = accept(this->sockClient, NULL, NULL);
		if (this->msg_sockClient == -1)
		{
			perror("Erreur accept");
		}
		this->initNouveauClient();
		pthread_mutex_unlock(&mutexConnectionClient);
	}
	close(this->msg_sockClient);
	return 0;
}

void * Serveur::traiterClient()
{
	// réception
	pthread_mutex_lock(&mutex_msg_sockClient);	
	int socket1 = this->msg_sockClient;
	pthread_mutex_unlock(&mutex_msg_sockClient);
	char  message[1024];
	int longueurMessage;
	struct sockaddr_in from;
	from.sin_port = htons((u_short)this->portClient);
	unsigned int from_len= sizeof(from);
	if (getpeername(socket1, (struct sockaddr*)&from, &from_len) == -1)
	{
		perror("Erreur d'obtention du nom du correspondant connecte a la socket");
	}
	printf("Connexion avec %s : %d\n\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
	this->log("Nouvelle connexion");

	longueurMessage = read(socket1, message, 1023);
	if (longueurMessage == -1)
	{
		perror("Probleme read");
		exit(-1);
	}

	// decoupage	
	istringstream iss( message );
	string mot, tab[3];
	int i=0;
	while ( std::getline(iss, mot, ':' ) )
	{	
		tab[i] = mot;
		i++;
	}
	memset(message, 0, strlen (message)+1);

	//test si authentification
	if (strcmp(tab[0].c_str(), "connect") == 0)
	{
		this->log("Tentative d'authentification d'un nouveau client.");
		
		string code = this->seekUser(tab[1]);
		if (strcmp(tab[2].c_str(), code.c_str()) == 0)
		{
			// demande d'information aux serveurs de partie
			this->infoGame();
			// mise a jour des jetons des serveurs de parties
			this->initJeton();
			// on attend la reponse des serveurs de partie
			sleep(2);

			// construction du message a renvoyer au client
			// format du message :
			//   :info1:ip1:port1!jeton1;info2:ip2:port2:jeton2;...infoN:ipN:portN:jetonN:
			char nbJoueur[2];
			char nbPacman[2];
			char nbFantome[2];
			char portEcouteServeurPartie[5];
			char portLectureServeurPartie[5];

			
			strcat(message, "@");
			strcat(message, "ok");
			strcat(message, "@");

			list<Partie>::iterator i;
			for(i = gameList.begin(); i != gameList.end(); ++i)
			{
				sprintf(nbJoueur, "%d", i->getNbJoueur());
				sprintf(nbPacman, "%d", i->getNbPacman());
				sprintf(nbFantome, "%d", i->getNbFantome());
				sprintf(portEcouteServeurPartie, "%d", i->getPortEcoute());
				sprintf(portLectureServeurPartie, "%d", i->getPortLecture());

				strcat(message, nbJoueur);
				strcat(message, ":");
				strcat(message, nbPacman);
				strcat(message, ":");
				strcat(message, nbFantome);
				strcat(message, ":");
				strcat(message, i->getIP().c_str());
				strcat(message, ":");
				strcat(message, portEcouteServeurPartie);
				strcat(message, ":");
				strcat(message, portLectureServeurPartie);
				strcat(message, ":");
				strcat(message, i->getJeton().c_str());
				strcat(message, ";");
			}
				strcat(message, "@");

				this->log(tab[1]+" vient de se connecter");
		}
		else
		{
			// login ou mot de passe mauvais
			strcpy(message, "loginFailed");
			this->log("Authentification du joueur "+tab[1]+" echouee");
		}
	}

	// test si inscription
	else if (strcmp(tab[0].c_str(), "register") == 0)
	{
		this->log("Tentative d'inscription d'un nouveau joueur ("+tab[1]+").");
		if (strcmp(this->seekUser(tab[1]).c_str(), "") == 0)
		{
			this->registerUser(tab[1], tab[2]);
			this->log("Nouveau joueur "+tab[1]+" inscrit.");
			strcpy(message, "ok");
		}
		else if (strcmp(this->seekUser(tab[1]).c_str(), "") != 0)
		{
			// login deja existant
			this->log("Inscription du nouveau joueur "+tab[1]+" echoue.");
			printf("Login deja existant\n");
			strcpy(message, "registerFailed");
		}
	}


	// test si desinscription
	else if (strcmp(tab[0].c_str(), "unregister") == 0)
	{
		this->log("Tentative de desinscription du joueur ("+tab[1]+").");

		string code = this->seekUser(tab[1]);
		if (strcmp(tab[2].c_str(), code.c_str()) == 0)
		{
			this->unRegisterUser(tab[1]);
			this->log("Desinscription du joueur "+tab[1]+" reussie.");
			strcpy(message, "ok");
		}
		else
		{
			// desinscription echouee
			this->log("Desinscription du joueur "+tab[1]+" echoue.");
			printf("Desinscription echouee");
			strcpy(message, "unregisterFailed");
		}
	}


	// message errone
	else
	{
		// on envoie pas de message d'erreurs. on passe silencieusement...
		this->log("Erreur de traitement d'une connexion.");
		return NULL;
	}

	if (write(socket1, message, strlen(message)) == -1)
	{
		perror("Erreur ecriture");
	}

	close(socket1);

	return NULL;
}

int * Serveur::lectureServeurPartie()
{
	while(1)
	{
		pthread_mutex_lock(&mutexLectureServeurPartie);
		this->msg_sockLectureServeurPartie = accept(this->sockLectureServeurPartie, NULL, NULL);
		if (this->msg_sockLectureServeurPartie == -1)
		{
			perror("Erreur accept");
		}
		this->initTraiteServeurPartie();
		pthread_mutex_unlock(&mutexLectureServeurPartie);
	}
	close(this->msg_sockLectureServeurPartie);
	return 0;	
}

void * Serveur::traiterServeurPartie()
{	
	// réception
	pthread_mutex_lock(&mutex_msg_sockLectureServeurPartie);
	int socket1 = this->msg_sockLectureServeurPartie;
	pthread_mutex_unlock(&mutex_msg_sockLectureServeurPartie);
	char message[1024];
	int msg_len;
	struct sockaddr_in from;
	from.sin_port = htons((u_short)this->portLectureServeurPartie);
	unsigned int from_len= sizeof(from);
	getpeername(socket1, (struct sockaddr*)&from, &from_len);
	printf("Connexion avec %s : %d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));

	msg_len= read(socket1, message, 1023);

	// decoupage
	istringstream iss( message );
	string mot, tab[4];
	int i=0;
	while ( std::getline(iss, mot, ':' ) )
	{	
		tab[i] = mot;
		i++;
	}

	// le serveur de partie vient d'envoyer les informations demandé par le serveur principal
	if (strcmp(tab[0].c_str(), "MyInfo") == 0)
	{
		list<Partie>::iterator i;
		for(i = gameList.begin(); i != gameList.end(); ++i)
		{
			if (i->getIP() == inet_ntoa(from.sin_addr))
			{
				i->setNbJoueur(atoi(tab[1].c_str()));
				i->setNbPacman(atoi(tab[2].c_str()));
				i->setNbFantome(atoi(tab[3].c_str()));
			}
		}
		return NULL;
	}

	// le serveur de partie envoie ce message  afin de montrer qu'il n'est pas planté
	else if (strcmp(message, "ImAlive") == 0)
	{
		list<Partie>::iterator i;
		for(i = gameList.begin(); i != gameList.end(); ++i)
		{
			if (i->getIP() == inet_ntoa(from.sin_addr))
			{
				i->setAlive(true);
			}
		}
		return NULL;
	}
	else
		// on envoie pas de message d'erreurs. on passe silencieusement...
		return NULL;

	//close(msgsock);
	close(socket1);

	// envoie de la réponse
	int sock;
	string NomDistant = inet_ntoa(from.sin_addr);
	struct sockaddr_in adresse;
	struct hostent *recup;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("Erreur ouverture");
	}

	if ((recup = gethostbyname(NomDistant.c_str())) == NULL)
	{
		perror("Erreur obtention adresse");
	}

	memcpy((char *)&adresse.sin_addr, (char *)recup->h_addr, recup->h_length);

	adresse.sin_family = AF_INET;
	adresse.sin_port = htons((u_short)this->portEcouteServeurPartie);
	if (connect(sock, (struct sockaddr *)&adresse, sizeof(adresse)) == -1)
	{
		perror("Erreur connexion");
	}
	if (write(sock, message, strlen(message)) == -1)
	{
		perror("Erreur ecriture");
	}

	close(sock);

	return NULL;
}

void * Serveur::infoGame()
{
	string NomDistant;
	struct sockaddr_in adresse;
	struct hostent *recup;
	int sock;

	string message = "sendMeInfo";

	list<Partie>::iterator i;

	for(i = gameList.begin(); i != gameList.end(); ++i)
	{
		NomDistant = i->getIP();

		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		{
			perror("Erreur ouverture");
			return NULL;
		}
		if ((recup = gethostbyname(NomDistant.c_str())) == NULL)
		{
			perror("Erreur obtention adresse");
			return NULL;
		}
		memcpy((char *)&adresse.sin_addr, (char *)recup->h_addr, recup->h_length);

		adresse.sin_family = AF_INET;
		adresse.sin_port = htons((u_short)this->portEcouteServeurPartie);
		if (connect(sock, (struct sockaddr *)&adresse, sizeof(adresse)) == -1)
		{
			perror("Erreur connexion");
			return NULL;
		}
		if (write(sock, message.c_str(), strlen(message.c_str())) == -1)
		{
			perror("Erreur ecriture");
			return NULL;
		}
		close(sock);
	}
	return 0;
}

void * Serveur::sendJeton()
{
	string NomDistant;
	struct sockaddr_in adresse;
	struct hostent *recup;
	int sock;

	char message[12];
	char nombreAleatoireString[3];
	int nombreAleatoireInt;

	// generation aleatoire d'un jeton pour chaque partie
	list<Partie>::iterator i;
	for(i = gameList.begin(); i != gameList.end(); ++i)
	{
		nombreAleatoireInt = hasard(1, 99);
		nombreAleatoireString[0] = '\0';
		sprintf(nombreAleatoireString, "%d", nombreAleatoireInt);
		i->setJeton(nombreAleatoireString);
		memset (nombreAleatoireString, 0, strlen(nombreAleatoireString));
	}
	// on envoie le jeton aux parties
	for(i = gameList.begin(); i != gameList.end(); ++i)
	{
		NomDistant = i->getIP();

		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		{
			perror("Erreur ouverture");
			return NULL;
		}
		if ((recup = gethostbyname(NomDistant.c_str())) == NULL)
		{
			perror("Erreur obtention adresse");
			return NULL;
		}
		memcpy((char *)&adresse.sin_addr, (char *)recup->h_addr, recup->h_length);

		adresse.sin_family = AF_INET;
		adresse.sin_port = htons((u_short)this->portEcouteServeurPartie);
		if (connect(sock, (struct sockaddr *)&adresse, sizeof(adresse)) == -1)
		{
			perror("Erreur connexion");
			return NULL;
		}

		memset (message, 0, sizeof (message));
		strcpy(message, "jeton:");
		strcat(message, i->getJeton().c_str());

		if (write(sock, message, strlen(message)) == -1)
		{
			perror("Erreur ecriture");
			return NULL;
		}
		close(sock);
	}
	return 0;
}

void * Serveur::testPresenceServeur()
{
	struct sockaddr_in adresse;
	struct hostent *recup;
	string nomDistant, nickname, type;
	string message = "AreYouAlive?";


	while (1)
	{
		sleep(5);

		// parcours de la liste des joueurs
		list<Partie>::iterator i;
		for(i = gameList.begin(); i != gameList.end(); ++i)
		{
				nomDistant = i->getIP();
				
				// on initialise le booleen de presence a false pour tous les serveurs 
				i->setAlive(false);
	
				if ((this->sockEcriture = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
				{
					perror("Erreur ouverture");
				}
	
				if ((recup = gethostbyname(nomDistant.c_str())) == NULL)
				{
					perror("Erreur obtention adresse");
				}
	
				memcpy((char *)&adresse.sin_addr, (char *)recup->h_addr, recup->h_length);
	
				adresse.sin_family = AF_INET;
				adresse.sin_port = htons((u_short)2332);
	
				if (connect(this->sockEcriture, (struct sockaddr *)&adresse, sizeof(adresse)) == -1)
				{
					perror("Erreur connect");
				}
	
				if ((sendto(this->sockEcriture, message.c_str(), strlen(message.c_str()), 0, NULL, 0)) == -1)
				{
					perror("Erreur ecriture");
				}

				close(this->sockEcriture);
	
		}
		
		// on laisse le temps aux serveurs de partie de répondre
		sleep (3);
		// on vérifie qui a répondu
		for(i = gameList.begin(); i != gameList.end(); ++i)
		{
			if (i->getAlive() == false)
			{
				printf("Le serveur de partie %s ne répond pas.\nIl se peut qu'il ait planté.\n\n", i->getIP().c_str());
				printf("Supprimé de la liste des serveurs de partie.");
				this->delGame(i->getIP());
				break;
			}
		}
	}
	message.clear();
	return NULL;
}


int Serveur::createSock(u_short port)
{
	int sock, retour;
	struct sockaddr_in adresse;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock<0)
	{
		perror ("Erreur ouverture");
		return(-1);
	}

	adresse.sin_family = AF_INET;
	adresse.sin_port = htons((u_short)port);
	adresse.sin_addr.s_addr = INADDR_ANY;

	retour = bind (sock, (struct sockaddr *)&adresse, sizeof(adresse));

	if (retour<0)
	{
		perror ("Impossible de nommer le socket");
		return(-1);
	}
	return (sock);
}

int Serveur::addGame(Partie partie)
{
	pthread_mutex_lock(&mutexAjoutPartie);
	if (this->numberOfGame < this->maxGame)
	{
		this->gameList.push_back(partie);
		this->numberOfGame++;
		pthread_mutex_unlock(&mutexAjoutPartie);
		return 0;
	}
	pthread_mutex_unlock(&mutexAjoutPartie);
	return -1;
}

int Serveur::delGame(string adresse)
{
	pthread_mutex_lock(&mutexSupprimePartie);
	list<Partie>::iterator i;
	for(i = gameList.begin(); i != gameList.end(); ++i)
	{
		if (i->getIP() == adresse)
		{
			this->gameList.erase(i);
			this->numberOfGame--;
			pthread_mutex_unlock(&mutexSupprimePartie);
			return 0;
		}
	}
	pthread_mutex_unlock(&mutexSupprimePartie);
	return 0;
}

int Serveur::getNumberOfGame()
{
	return this->gameList.size();
}

void Serveur::close_serveur(int sock)
{
	close(sock);
}

string Serveur::seekUser(string login)
{	
	ifstream file;
	string fichier = "passwd";
	file.open(fichier.c_str(), ios::in);
	string ligne;
	int nbLigne = 0;
	string code = "";

	if ( file ) // ce test echoue si le fichier n'est pas ouvert
	{
		std::string ligne; // variable contenant chaque ligne lue

		// cette boucle s'arrête dès qu'une erreur de lecture survient
		while ( std::getline( file, ligne ) )
		{
			nbLigne++;

			istringstream iss( ligne );
			string mot, utilisateur[2];
			int i=0;
			while ( std::getline( iss, mot, ':' ) )
			{	
				utilisateur[i] = mot;
				i++;
			}

			if (utilisateur[0] == login)
			{
				code = utilisateur[1];
				file.close();
				return code;
			}
		}
		file.close();
	}
	return code;
}

void Serveur::registerUser(string login, string code)
{
	ofstream file;
	string fichier = "passwd";

	//app (append) Set the stream's position indicator to the end of the stream before each output operation.
	//ate (at end) Set the stream's position indicator to the end of the stream on opening.

	file.open(fichier.c_str(), ios::out | ios::ate | ios::app);

	if (file.bad())
	{
		cerr << "Fichier [" << fichier << "] invalide." << endl;
		exit(-1);
	}
	if (file.is_open())
    {
        // Écrit les données :
		file << login << ":" << code << endl;

		file.close();
    }
}

void Serveur::unRegisterUser(string login)
{
	ifstream file;
	ofstream fileTemp;
	string fichier = "passwd";
	string fichierTemp = "tmp";
	file.open(fichier.c_str(), ios::in);
	fileTemp.open(fichierTemp.c_str(), ios::out | ios::ate | ios::app);
	string ligne;
	string code = "";

	// on recopie les lignes des autres utilisateurs dans un fichier temporaire
	if ( file and fileTemp)
	{
		std::string ligne;

		while ( std::getline( file, ligne ) )
		{

			istringstream iss( ligne );
			string mot, utilisateur[2];
			int i=0;
			while ( std::getline( iss, mot, ':' ) )
			{	
				utilisateur[i] = mot;
				i++;
			}

			if (utilisateur[0] != login)
			{
				fileTemp << ligne << endl;
			}
		}
		file.close();
		fileTemp.close();
	}


	// on écrase le contenu de passwd avec celui du fichier temporaire
	file.open(fichierTemp.c_str(), ios::in);
	fileTemp.open(fichier.c_str(), ios::out);
	if (file.bad() or fileTemp.bad())
	{
		cerr << "Erreur d'ecriture ou lecture" << endl;
		exit(-1);
	}
	if (file.is_open())
    {
		while ( std::getline(file, ligne) )
		{
			fileTemp << ligne << endl;
		}

		file.close();
		fileTemp.close();

		// suppression du fichier temporaire
		if(remove( "tmp" ) != 0)
			printf("Erreur lors de la suppression du fichier temporaire tmp\n");
	}
}

void Serveur::log(string message)
{
	pthread_mutex_lock(&mutexLog);
	// récupère l'heure système
	time_t timer1;
	time(&timer1);
	int secondes, minutes, heures;
	string fichier = "log";
	struct tm *newTime1;
	newTime1 = localtime(&timer1);
	heures = newTime1->tm_hour;
	minutes = newTime1->tm_min;
	secondes = newTime1->tm_sec;

	ofstream file;

	file.open(fichier.c_str(), ios::out | ios::ate | ios::app);

	if (file.bad())
	{
		cerr << "Fichier [" << fichier << "] invalide." << endl;
		pthread_mutex_unlock(&mutexLog);
		exit(-1);
	}
	if (file.is_open())
    {
        // Écrit les données :
		file << "[" << heures << ":" << minutes << ":" << secondes << "] " << message << endl;
        
        file.close();
    }
    pthread_mutex_unlock(&mutexLog);
}
